################################################################################
#
#Copyright (c) 2012, Petr Skramovsky
#All rights reserved.
#
#Redistribution and use in source and binary forms, with or without
#modification, are permitted provided that the following conditions are met:
#    * Redistributions of source code must retain the above copyright
#      notice, this list of conditions and the following disclaimer.
#    * Redistributions in binary form must reproduce the above copyright
#      notice, this list of conditions and the following disclaimer in the
#      documentation and/or other materials provided with the distribution.
#
#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
#ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
#WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
#DISCLAIMED. IN NO EVENT SHALL Petr Skramovsky BE LIABLE FOR ANY
#DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
#(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
#LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
#ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
#(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
#SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
################################################################################

import c4d
import math
import bsp
import bsp_util
import os
from shader import *
from qsystem import QFileSystem


IMG_EXTS = [ ".jpg", ".jpeg", ".png", ".tga" ]

def make_material(doc,fs,tex):
  name = tex.name.split("/")[-1]
  fex = ""
  for ex in IMG_EXTS:
    if fs[ tex.name + ex ]:
      fex = ex
      break
  epath = os.path.join( doc.GetDocumentPath(), tex.name.replace("/","\\") + ex )
  fs.extract( tex.name + ex, doc.GetDocumentPath() )
  mat = c4d.BaseMaterial(c4d.Mmaterial)
  shd = c4d.BaseList2D(c4d.Xbitmap)
  shd[c4d.BITMAPSHADER_FILENAME] = epath
  mat[c4d.MATERIAL_COLOR_SHADER] = shd
  #if ex in [".png", ".tga"] :
    #mat[c4d.MATERIAL_USE_ALPHA]=True
    #mat[c4d.MATERIAL_ALPHA_SHADER] = shd
  mat[c4d.MATERIAL_USE_SPECULAR] = False
  mat.SetName(name)
  mat.InsertShader(shd)
  mat.Message(c4d.MSG_UPDATE)
  mat.Update(True, True)
  return mat

def make_c4d_map( doc, fs, map_name, cquality ):
  if doc.SearchObject(map_name) != None:
    return

  map = fs[ map_name ]
  root_object = c4d.BaseObject(c4d.Onull)
  root_object.SetName(map_name)

  mats = []
  for i in range(0,len(map.textures)):
    m = make_material(doc,fs,map.textures[i])
    doc.InsertMaterial(m)
    mats.append(m)

  polys = []
  uvs = []
  for i in range(0, len(map.textures)):
    p = c4d.PolygonObject(0, 0)
    uv = c4d.UVWTag(0)
    uv[c4d.UVWTAG_LOCK] = True
    p.SetPhong(True, 1, math.radians(80.0))
    p.InsertTag(uv)
    polys.append(p)
    uvs.append(uv)

  for face in map.faces:
    if face.type == bsp.FACE_TYPE_MESH or face.type == bsp.FACE_TYPE_POLYGON:
      p = polys[face.texture]
      uv = uvs[face.texture]
      oi = p.GetPointCount()
      fi = p.GetPolygonCount()
      p.ResizeObject(oi + face.n_meshverts + 1, fi + int(face.n_meshverts / 3))
      pts = []
      for i in range(0, face.n_meshverts):
        if i % 3 == 0 and i != 0:
          ci = oi + i
          p.SetPolygon(id=fi, polygon=c4d.CPolygon(ci-3, ci-2, ci-1))
          uv.SetSlow(fi, c4d.Vector(pts[0].texcoord[0][0], pts[0].texcoord[0][1], 0), \
                     c4d.Vector(pts[1].texcoord[0][0], pts[1].texcoord[0][1], 0), \
                     c4d.Vector(pts[2].texcoord[0][0], pts[2].texcoord[0][1], 0), c4d.Vector())
          fi += 1
          pts = []
        pi = face.vertex + map.meshverts[face.meshvert + i]
        pt = map.vertexes[pi]
        pts.append(pt)
        p.SetPoint(oi + i, c4d.Vector(-pt.position[0], pt.position[1], pt.position[2]))
      p.SetPolygon(id=fi, polygon=c4d.CPolygon(oi + face.n_meshverts-3, oi + face.n_meshverts-2, oi + face.n_meshverts-1))
      uv.SetSlow(fi, c4d.Vector(pts[0].texcoord[0][0], pts[0].texcoord[0][1], 0), \
                 c4d.Vector(pts[1].texcoord[0][0], pts[1].texcoord[0][1], 0), \
                 c4d.Vector(pts[2].texcoord[0][0], pts[2].texcoord[0][1], 0), c4d.Vector())
    elif face.type == bsp.FACE_TYPE_PATCH:
      bs = bsp_util.get_bezier(map, face, cquality)
      p = polys[face.texture]
      uv = uvs[face.texture]
      for b in bs:
        oi = p.GetPointCount()
        fi = p.GetPolygonCount()
        tot = len(b.index)
        p.ResizeObject(oi + tot, fi + int(tot / 3))
        pts = []
        for i in range(0, tot):
          if i % 3 == 0 and i != 0:
            ci = oi + i
            p.SetPolygon(id=fi, polygon=c4d.CPolygon(ci-3, ci-2, ci-1))
            uv.SetSlow(fi, c4d.Vector(pts[0].texcoord[0][0], pts[0].texcoord[0][1], 0), \
                       c4d.Vector(pts[1].texcoord[0][0], pts[1].texcoord[0][1], 0), \
                       c4d.Vector(pts[2].texcoord[0][0], pts[2].texcoord[0][1], 0), c4d.Vector())
            fi += 1
            pts = []
          pi = b.index[i]
          pt = b.verts[pi]
          pts.append(pt)
          p.SetPoint(oi + i, c4d.Vector(-pt.position[0], pt.position[1], pt.position[2]))
        p.SetPolygon(id=fi, polygon=c4d.CPolygon(oi + tot-3, oi + tot-2, oi + tot-1))
        uv.SetSlow(fi, c4d.Vector(pts[0].texcoord[0][0], pts[0].texcoord[0][1], 0), \
                   c4d.Vector(pts[1].texcoord[0][0], pts[1].texcoord[0][1], 0), \
                   c4d.Vector(pts[2].texcoord[0][0], pts[2].texcoord[0][1], 0), c4d.Vector())
    else:
      print "billboarding is not supported"

  for i in range(0, len(map.textures)):
    p = polys[i]
    doc.SetActiveObject(p,c4d.SELECTION_ADD)
    p.SetName(str(i))
    mtag = c4d.TextureTag()
    mtag.SetMaterial(mats[i])
    mtag[c4d.TEXTURETAG_PROJECTION] = c4d.TEXTURETAG_PROJECTION_UVW
    p.InsertTag(mtag)
    p.InsertUnder(root_object)

  root_object.SetAbsRot(c4d.Vector(math.pi,math.pi/2,0))
  doc.InsertObject(root_object)
  
  c4d.CallCommand(12139)
  c4d.CallCommand(13323)
  c4d.CallCommand(14039)
  doc.SetChanged()

fs = QFileSystem("C:\\Program Files (x86)\\Quake III Arena")
make_c4d_map(doc, fs, "maps/coldrun.bsp", 5)